﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using System.Windows.Forms;
using System.Threading;

namespace DivisonsCodeTools.Business
{
    /// <summary>
    /// 采集方法
    /// </summary>
    public sealed class DivisonBus
    {
        Thread thread;

        public Form form { get; set; }

        public RichTextBox richTextBox { get; set; }

        #region 私有方法
        /// <summary>
        /// GetHtmlNodeCollection
        /// </summary>
        /// <param name="url"></param>
        /// <param name="searchStr"></param>
        /// <returns></returns>
        private HtmlNodeCollection GetHtmlNodeCollection(string url, string searchStr)
        {
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            HtmlNodeCollection collection = null;
            string html = GetHtml(url);
            if (!string.IsNullOrEmpty(html))
            {
                doc.LoadHtml(html);
                collection = doc.DocumentNode.SelectNodes(searchStr);
            }
            return collection;
        }

        /// <summary>
        /// GetHtml
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private string GetHtml(string url)
        {
            try
            {
                WebRequest rGet = WebRequest.Create(url);
                WebResponse rSet = rGet.GetResponse();
                Stream s = rSet.GetResponseStream();
                StreamReader reader = new StreamReader(s, Encoding.Default);
                return reader.ReadToEnd();
            }
            catch (WebException)
            {
                //连接失败
                return null;
            }
        }
        /// <summary>
        /// 取Index页面的数据
        /// </summary>
        /// <returns></returns>
        private string GetIndexUrl()
        {
            HtmlNodeCollection collection = GetHtmlNodeCollection(Configure.Config.GetInstance().Url, "//ul[@class='center_list_contlist']").FirstOrDefault().SelectNodes("li").FirstOrDefault().SelectNodes("a");
            string reslutUrl = "";
            if (collection != null)
            {
                HtmlNode node = collection.FirstOrDefault();
                string temvalue = node.GetAttributeValue("href", "");
                reslutUrl = "http://www.stats.gov.cn/" + temvalue.Substring(temvalue.IndexOf("/") + 1);
            }
            return reslutUrl;
        }
        /// <summary>
        /// 取省
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private List<DivisonInfo> GetProvince(string url)
        {
            List<DivisonInfo> list = new List<DivisonInfo>();
            HtmlNodeCollection collection = GetHtmlNodeCollection(url, "//tr[@class = 'provincetr']/td");
            if (null != collection)
            {
                foreach (var item in collection)
                {
                    DivisonInfo info = new DivisonInfo();
                    info.Name = item.InnerText;
                    string urlNext = item.FirstChild.Attributes["href"].Value;
                    info.Code = urlNext.Substring(0, urlNext.IndexOf(".")) + "0000000000";
                    info.ParentCode = "";
                    info.UrlNext = url.Substring(0, url.IndexOf("index")) + urlNext;
                    info.Level = (int)Divisonlevel.Province;
                    list.Add(info);
                }
            }
            return list;
        }

        /// <summary>
        /// 取市
        /// </summary>
        /// <param name="url"></param>
        /// <param name="ParentCode"></param>
        /// <returns></returns>
        private List<DivisonInfo> GetCity(string url, string ParentCode)
        {
            List<DivisonInfo> list = new List<DivisonInfo>();
            HtmlNodeCollection collection = GetHtmlNodeCollection(url, "//tr[@class = 'citytr']");
            if (null != collection)
            {
                foreach (var item in collection)
                {
                    DivisonInfo info = new DivisonInfo();
                    List<HtmlNode> HtmlNodelist = item.Elements("td").ToList();
                    if (null != HtmlNodelist && HtmlNodelist.Count == 2)
                    {
                        info.Code = HtmlNodelist[0].InnerText;
                        info.Name = HtmlNodelist[1].InnerText;
                        string temurl = HtmlNodelist[0].Elements("a").ToList()[0].Attributes["href"].Value;
                        info.ParentCode = ParentCode;
                        info.Level = (int)Divisonlevel.City;
                        info.UrlNext = url.Substring(0, url.LastIndexOf(".") - 2) + temurl;
                        list.Add(info);
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 取区
        /// </summary>
        /// <param name="url"></param>
        /// <param name="ParentCode"></param>
        /// <returns></returns>
        private List<DivisonInfo> GetArea(string url, string ParentCode)
        {
            List<DivisonInfo> list = new List<DivisonInfo>();
            HtmlNodeCollection collection = GetHtmlNodeCollection(url, "//tr[@class = 'countytr']");
            if (null != collection)
            {
                foreach (HtmlNode tr in collection)
                {
                    DivisonInfo info = new DivisonInfo();
                    List<HtmlNode> tdlist = tr.Elements("td").ToList();
                    if (null != tdlist && tdlist.Count == 2)
                    {
                        info.Code = tdlist[0].InnerText;
                        info.Name = tdlist[1].InnerText;
                        if (tdlist[0].Elements("a").ToList().Count > 0)
                        {
                            string temurl = tdlist[0].Elements("a").ToList()[0].Attributes["href"].Value;
                            info.ParentCode = ParentCode;
                            info.Level = (int)Divisonlevel.Area;
                            info.UrlNext = url.Substring(0, url.LastIndexOf(".") - 4) + temurl;
                            list.Add(info);
                        }
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 取街道
        /// </summary>
        /// <param name="url"></param>
        /// <param name="ParentCode"></param>
        /// <returns></returns>
        private List<DivisonInfo> GetStreet(string url, string ParentCode)
        {
            List<DivisonInfo> list = new List<DivisonInfo>();
            HtmlNodeCollection collection = GetHtmlNodeCollection(url, "//tr[@class = 'towntr']");
            if (null != collection)
            {
                foreach (HtmlNode tr in collection)
                {
                    DivisonInfo info = new DivisonInfo();
                    List<HtmlNode> tdlist = tr.Elements("td").ToList();
                    if (null != tdlist && tdlist.Count == 2)
                    {
                        string code = tdlist[0].InnerText;
                        string name = "";
                        if (tdlist[1].InnerText.IndexOf("办事处") != -1)
                        {
                            name = tdlist[1].InnerText.Substring(0, tdlist[1].InnerText.IndexOf("办事处"));
                        }
                        else
                        {
                            name = tdlist[1].InnerText;
                        }
                        string temurl = tdlist[0].Elements("a").ToList()[0].Attributes["href"].Value;
                        info.ParentCode = ParentCode;
                        info.Level = (int)Divisonlevel.Street;
                        info.Code = code;
                        info.Name = name;
                        info.UrlNext = url.Substring(0, url.LastIndexOf(".") - 6) + temurl;
                        list.Add(info);
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 取居委
        /// </summary>
        /// <param name="url"></param>
        /// <param name="ParentCode"></param>
        /// <returns></returns>
        private List<DivisonInfo> GetCommunity(string url, string ParentCode)
        {
            List<DivisonInfo> list = new List<DivisonInfo>();
            HtmlNodeCollection collection = GetHtmlNodeCollection(url, "//tr[@class = 'villagetr']");
            if (null != collection)
            {
                foreach (HtmlNode tr in collection)
                {
                    List<HtmlNode> tdlist = tr.Elements("td").ToList();
                    if (null != tdlist && tdlist.Count == 3)
                    {
                        string code = tdlist[0].InnerText;
                        string name = tdlist[2].InnerText;
                        DivisonInfo tem = new DivisonInfo();
                        tem.ParentCode = ParentCode;
                        tem.Level = (int)Divisonlevel.Community;
                        tem.Code = code;
                        tem.Name = name;
                        list.Add(tem);
                    }
                }
            }
            return list;
        }
        #endregion

        #region 公共方法

        public void Start()
        {
            //开始执行
            thread = new Thread(new ThreadStart(GetDivison));
            thread.IsBackground = true;
            thread.Start();
        }
        public void Stop()
        {
            if (null != thread)
            {
                thread.Abort();
            }
        }
        private void MyRefresh(string str)
        {
            try
            {
                form.Invoke((MethodInvoker)delegate()
                {
                    richTextBox.AppendText(str);
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        /// <summary>
        /// 采集行政区域代码
        /// </summary>
        /// <returns></returns>
        public void GetDivison()
        {
            List<DivisonInfo> provincelist = GetProvince(GetIndexUrl());
            if (provincelist != null)
            {
                SaveJson(ToJson(provincelist));
                for (int i = 0; i < provincelist.Count; i++)
                {
                    List<DivisonInfo> citylist = GetCity(provincelist[i].UrlNext, provincelist[i].Code);
                    if (citylist != null && citylist.Count > 0)
                    {
                        SaveJson(ToJson(citylist));
                        for (int m = 0; m < citylist.Count; m++)
                        {
                            List<DivisonInfo> Arealist = GetArea(citylist[m].UrlNext, citylist[m].Code);
                            if (Arealist != null && Arealist.Count > 0)
                            {
                                SaveJson(ToJson(Arealist));
                                for (int k = 0; k < Arealist.Count; k++)
                                {
                                    List<DivisonInfo> steetlist = GetStreet(Arealist[k].UrlNext, Arealist[k].Code);
                                    if (steetlist != null && steetlist.Count > 0)
                                    {
                                        SaveJson(ToJson(steetlist));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            MessageBox.Show("采集完毕!");
        }

        public bool MariaDBSave()
        {
            bool sucess = false;
            string file = Configure.Config.GetInstance().FilePath + Configure.Config.GetInstance().FileName;
            if (File.Exists(file))
            {
                StreamReader sr = new StreamReader(file);
                string json = "";
                json = sr.ReadToEnd();
                List<DivisonInfo> list = JsonConvert.DeserializeObject<List<DivisonInfo>>(json);
                sr.Close();
                sr.Dispose();
                int pageindex = 1;
                int pagesize = 4000;
                int pagecount = list.Count;
                int sum = pagecount / pagesize;
                if (pagecount % pagesize != 0)
                    sum += 1;
                for (pageindex = 1; pageindex <= sum; pageindex++)
                {
                    List<DivisonInfo> temlist = list.Skip((pageindex - 1) * pagesize).Take(pagesize).ToList();
                    Log.WriteLog("开始使用InsertBathForSQL方法");
                    sucess = SaveList(temlist);
                    Log.WriteLog("结束使用InsertBathForSQL方法");
                }
            }
            return sucess;
        }

        /// <summary>
        /// 生成json
        /// </summary>
        /// <param name="list"></param>
        private string ToJson(List<DivisonInfo> list)
        {
            string json = "";
            for (int i = 0; i < list.Count; i++)
            {
                json += JsonConvert.SerializeObject(list[i]) + ",\n";
                string msg = JsonConvert.SerializeObject(list[i]) + ",\n";
                MyRefresh(msg);
            }
            if (json.Length > 0)
            {
                json = json.Substring(0, json.Length - 1);
            }

            return json;
        }



        private bool SaveList(List<DivisonInfo> list)
        {
            DataBase db = new DataBase(Configure.Config.GetInstance().MariadbConnectionString);
            return db.InsertBatch(list, Configure.Config.GetInstance().MariadbTableName);
        }

        /// <summary>
        /// 保存Json
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        private bool SaveJson(string json)
        {
            bool sucess = false;
            string file = Configure.Config.GetInstance().FilePath + "\\" + Configure.Config.GetInstance().FileName;
            StreamWriter fs = new StreamWriter(file, true);
            fs.WriteLine(json);
            fs.Close();
            return sucess;
        }

        #endregion

    }
    public enum Divisonlevel
    {
        /// <summary>
        /// 省 一级
        /// </summary>
        Province = 1,
        /// <summary>
        /// 市 二级
        /// </summary>
        City = 2,
        /// <summary>
        /// 区 三级
        /// </summary>
        Area = 3,
        /// <summary>
        /// 街道 四级
        /// </summary>
        Street = 4,
        /// <summary>
        /// 居委 五级
        /// </summary>
        Community = 5
    }

    [JsonObject(MemberSerialization.OptOut)]
    public class DivisonInfo
    {
        public string Name { get; set; }
        public string Code { get; set; }
        public int Level { get; set; }
        public string ParentCode { get; set; }
        public string Remark { get; set; }
        [JsonIgnore]
        public string UrlNext { get; set; }
    }
}
